package com.me.study.jdk8.stream;

import com.me.study.jdk8.lambda.Apple;
import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import static org.junit.Assert.*;

/**
 * Java8：Stream API 测试
 *
 * @author ME
 * @date 2021/4/26
 */
public class TestStreamAPI {

    private static List<Integer> list;
    private List<Apple> appleList = new ArrayList<>(4);

    @Test
    public void peek() {
        // peek 方法的参数 apple 是栈里的引用变量，它持有对象的引用，修改 apple 的引用就指向了新对象，对原始对象无影响
        List<String> appleNew = appleList.stream().peek(apple -> {
            apple = new Apple(apple.getName() + "2333", "", 0, "");
        }).map(Apple::getName).collect(Collectors.toList());
        assertEquals("处理后的集合：",
                "[红富士, 金帅, 蛇果]", appleNew.toString());

        // 通过 apple 的引用拿到原始对象，直接修改可以修改原始对象
        appleNew = appleList.stream().peek(apple -> {
            apple.setName(apple.getName() + "2333");
        }).map(Apple::getName).collect(Collectors.toList());
        assertEquals("处理后的集合：",
                "[红富士2333, 金帅2333, 蛇果2333]", appleNew.toString());
    }

    @Test
    public void map() {
        List<String> listNew = appleList.stream().map(Apple::getName).collect(Collectors.toList());
        Set<String> setNew = appleList.stream().map(Apple::getName).collect(Collectors.toSet());

        assertEquals("处理后的集合：",
                "[红富士, 金帅, 蛇果]", listNew.toString());
    }

    @Test
    public void flatMap() {
        List<String> list1 = Arrays.asList("m", "k", "l", "a");
        List<String> list2 = Arrays.asList("1", "3", "5", "7");
        List<List<String>> list = Arrays.asList(list1, list2);
        List<String> listNew = list.stream().flatMap(entity -> {
                // 将每个元素转换成 stream
                return entity.stream();
            }).collect(Collectors.toList());

        assertEquals("处理后的集合：",
                "[m, k, l, a, 1, 3, 5, 7]", listNew.toString());
    }

    @Test
    public void distinct() {
        final List<Integer> collect = list.stream().distinct().collect(Collectors.toList());
        assertEquals("去重：",
                "[7, 6, 9, 3, 12, 2]", collect.toString());
    }

    @Test
    public void limit() {
        final List<Integer> collect = list.stream().limit(4).collect(Collectors.toList());
        assertEquals("截取前 n个元素：",
                "[7, 6, 9, 3]", collect.toString());
    }

    @Test
    public void skip() {
        final List<Integer> collect = list.stream().skip(3).collect(Collectors.toList());
        assertEquals("跳过前 n个元素：",
                "[3, 12, 2, 3]", collect.toString());
    }

    @Test
    public void max() {
        // max/min/count
        Optional<Integer> max = list.stream().max(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                // -1--小于
                return o1.compareTo(o2);
            }
        });
        assertEquals("自然排序的最大值：12",
                Integer.valueOf(12), max.get());
    }

    /** 统计总数 */
    @Test
    public void count() {
        assertEquals("list中大于6的元素个数：3",
                3, list.stream().filter(x -> x > 6).count());
    }

    /** 遍历 */
    @Test
    public void foreach() {
        list.stream().forEach(System.out::println);
        System.out.println();
    }

    /** 查找第一个 */
    @Test
    public void find() {
        assertEquals("查找第一个",
                Integer.valueOf(7), list.stream().findFirst().get());
        assertNotNull("查找任意一个", list.stream().findAny().get());
    }

    /** 统计总数 */
    @Test
    public void match() {
        assertFalse("不存在 大于20 的元素", list.stream().anyMatch(x -> x > 20));
        assertTrue("不存在 大于20 的元素", list.stream().noneMatch(x -> x > 20));
    }

    @Test
    public void filter() {
        assertEquals("过滤 大于7 的元素",
                Integer.valueOf(9), list.stream().filter(x -> x > 7).findFirst().get());
    }

    @Before
    public void initStream() {
        // 用集合创建流
        TestStreamAPI.list = Arrays.asList(7, 6, 9, 3, 12, 2, 3);
        Stream<Integer> stream = list.stream();
        Stream<Integer> parallelStream = list.parallelStream();

        // 用数组创建流
        int[] array = {1, 3, 5, 6, 8};
        IntStream stream2 = Arrays.stream(array);

        // 使用Stream的静态方法创建：of()、iterate()、generate()
        Stream<Integer> stream3 = Stream.of(1, 2, 3, 4, 5, 6);
        stream3 = Stream.iterate(0, (x) -> x + 3).limit(4); // 0 3 6 9
        Stream<Double> stream4 = Stream.generate(Math::random).limit(3);

        appleList.add(new Apple("红富士", "red", 300, "山东"));
        appleList.add(new Apple("金帅", "yellow", 180, "云南"));
        appleList.add(new Apple("蛇果", "red", 200, "美国"));
    }

}
